#include "virtual_adapter.h"

#define SDA_INPUT(i2c_bit)			gpio_direction_input((i2c_bit)->sda_gpio);
#define SDA_OUTPUT(i2c_bit, val)	gpio_direction_output((i2c_bit)->sda_gpio, (val))
#define SCL_OUTPUT(i2c_bit, val)	gpio_direction_output((i2c_bit)->scl_gpio, (val))

#define SDA_H(i2c_bit)				gpio_set_value((i2c_bit)->sda_gpio, 1)
#define SDA_L(i2c_bit)				gpio_set_value((i2c_bit)->sda_gpio, 0)

#define SCL_H(i2c_bit)				gpio_set_value((i2c_bit)->scl_gpio, 1)
#define SCL_L(i2c_bit)				gpio_set_value((i2c_bit)->scl_gpio, 0)

#define SET_SDA(i2c_bit, val)		((val)==0 ? SDA_L(i2c_bit) : SDA_H(i2c_bit))
#define GET_SDA(i2c_bit)			gpio_get_value((i2c_bit)->sda_gpio)

#define DELAY(i2c_bit)				udelay((i2c_bit)->delay_us >> 1)
#define DELAY2(i2c_bit)				udelay((i2c_bit)->delay_us)

static int adapter_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num);
static u32 adapter_func(struct i2c_adapter *adap);

static int adapter_probe(struct platform_device *pdev);
static int adapter_remove(struct platform_device *pdev);

static const struct i2c_algorithm adapter_algorithm = {
	.master_xfer = adapter_master_xfer,
	.functionality = adapter_func,
};

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id adapter_of_match[] = {
	{.compatible = "alientek,i2c-gpio"},
	{ /* Sentinel */ }
};
//平台驱动
static struct platform_driver adapter_drv = {
	.driver = {
		.name = "virtual_adapter",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = adapter_of_match,
	},
	.probe = adapter_probe,
	.remove = adapter_remove,
};
//适配器句柄
static virtual_adapter_t adapter_handle[ADAPTER_NUMBER];

static void _i2c_start(virtual_adapter_t *i2c_bit)
{
	/* assert: scl, sda are high */
	SDA_OUTPUT(i2c_bit, 0);
	DELAY(i2c_bit);
	SCL_L(i2c_bit);
	DELAY2(i2c_bit);
}

static void _i2c_restart(virtual_adapter_t *i2c_bit)
{
	/* assert: scl is low */
	SDA_OUTPUT(i2c_bit, 1);
	DELAY2(i2c_bit);
	SCL_H(i2c_bit);
	DELAY(i2c_bit);

	SDA_L(i2c_bit);
	DELAY(i2c_bit);
	SCL_L(i2c_bit);
	DELAY2(i2c_bit);
}

static void _i2c_stop(virtual_adapter_t *i2c_bit)
{
	SDA_OUTPUT(i2c_bit, 0);
	SCL_L(i2c_bit);
	DELAY2(i2c_bit);
	
	SCL_H(i2c_bit);
	DELAY(i2c_bit);
	SDA_H(i2c_bit);
	DELAY(i2c_bit);
}

static int32_t _i2c_waitack(virtual_adapter_t *i2c_bit, int32_t ignore_nack)
{
	int32_t ack;
	
	SDA_INPUT(i2c_bit)
	DELAY2(i2c_bit);
	SCL_H(i2c_bit);
	DELAY(i2c_bit);
	ack = GET_SDA(i2c_bit);
	SCL_L(i2c_bit);
	DELAY2(i2c_bit);
	if(ignore_nack)
		return 0;

	return (ack==0) ? 0 : -EIO;
}

static void _i2c_sendack(virtual_adapter_t *i2c_bit, int32_t ack)
{
	SDA_OUTPUT(i2c_bit, ack);
	DELAY2(i2c_bit);
	SCL_H(i2c_bit);
	DELAY(i2c_bit);
	SCL_L(i2c_bit);
	DELAY2(i2c_bit);
}

static int32_t _i2c_writeb(virtual_adapter_t *i2c_bit, uint8_t data, int32_t ignore_nack)
{
	int8_t i;
	uint8_t bit;

	for(i=7; i>=0; i--)
	{
		bit = (data >> i) & 1;
		if(i == 7)
			SDA_OUTPUT(i2c_bit, bit);
		else
			SET_SDA(i2c_bit, bit);
		DELAY2(i2c_bit);
		SCL_H(i2c_bit);
		DELAY(i2c_bit);
		SCL_L(i2c_bit);
		DELAY2(i2c_bit);
	}

	return _i2c_waitack(i2c_bit, ignore_nack);
}

static uint8_t _i2c_readb(virtual_adapter_t *i2c_bit, int32_t ack)
{
	int8_t i;
	uint8_t data;
	
	SDA_INPUT(i2c_bit)
	SDA_H(i2c_bit);
	DELAY2(i2c_bit);
	for(data=0,i=7; i>=0; i--)
	{
		SCL_H(i2c_bit);
		DELAY(i2c_bit);
		data |= GET_SDA(i2c_bit) << i;
		SCL_L(i2c_bit);
		if(i != 0)
			DELAY(i2c_bit);
		else
			DELAY2(i2c_bit);
	}
	_i2c_sendack(i2c_bit, ack);

	return data;
}

static ssize_t _i2c_send_bytes(virtual_adapter_t *i2c_bit, struct i2c_msg *msg)
{
	int32_t result;
	ssize_t bytes;
	uint16_t ignore_nack = msg->flags & I2C_M_IGNORE_NAK;

	for(bytes=0; bytes<msg->len; )
	{
		result = _i2c_writeb(i2c_bit, msg->buf[bytes], ignore_nack);
		if(result == 0) 
			bytes++;
		else 
			break;
	}

	return bytes;
}

static ssize_t _i2c_recv_bytes(virtual_adapter_t *i2c_bit, struct i2c_msg *msg)
{
	int32_t ack;
	ssize_t bytes;

	for(bytes=0; bytes<msg->len; bytes++)
	{
		if((msg->flags & I2C_M_NO_RD_ACK) || (bytes >= (msg->len-1)))
			ack = 1;
		else
			ack = 0;
		msg->buf[bytes] = _i2c_readb(i2c_bit, ack);
	}
	
	return bytes;
}

static int32_t _i2c_send_address(virtual_adapter_t *i2c_bit, struct i2c_msg *msg)
{
	uint8_t addr1;
	uint8_t addr2;
	int32_t result;
	uint16_t ignore_nack = msg->flags & I2C_M_IGNORE_NAK;

	if(msg->flags & I2C_M_TEN)
	{
		addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
		addr2 = msg->addr & 0xff;

		result = _i2c_writeb(i2c_bit, addr1, ignore_nack);
		if(result != 0)
			return result;
		result = _i2c_writeb(i2c_bit, addr2, ignore_nack);
		if(result != 0)
			return result;

		if(msg->flags & I2C_M_RD)
		{
			_i2c_restart(i2c_bit);
			addr1 |= 0x01;
			result = _i2c_writeb(i2c_bit, addr1, ignore_nack);
			if(result != 0) 
				return result;
		}
	}
	else {
		/* 7-bit addr */
		addr1 = msg->addr << 1;
		if(msg->flags & I2C_M_RD)
			addr1 |= 1;
		result = _i2c_writeb(i2c_bit, addr1, ignore_nack);
		if(result != 0)
			return result;
	}

	return 0;
}

static int adapter_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
	struct i2c_msg *msg;
	int result;
	virtual_adapter_t *i2c_bit = container_of(i2c_adap, virtual_adapter_t, adapter);

	for(result=0; result<num; result++)
	{
		msg = &msgs[result];

		//发送开始信号或重启信号
		if((!(msg->flags & I2C_M_NOSTART)) || (result == 0))
		{
			if(result == 0)
			{
				//产生开始信号
				_i2c_start(i2c_bit);
			}
			else
			{
				//产生重启信号
				_i2c_restart(i2c_bit);
			}
			//发送设备地址
			if(_i2c_send_address(i2c_bit, msg) != 0)
			{
				_i2c_stop(i2c_bit);
				break;
			}
		}

		//传输数据
		if(msg->flags & I2C_M_RD)
		{
			//读数据
			if(_i2c_recv_bytes(i2c_bit, msg) != msg->len)
			{
				_i2c_stop(i2c_bit);
				printk("recv data failed");
				break;
			}
		}
		else {
			//写数据
			if(_i2c_send_bytes(i2c_bit, msg) != msg->len)
			{
				_i2c_stop(i2c_bit);
				printk("send data failed");
				break;
			}
		}

		//产生停止信号
		if(((msg->flags & I2C_M_STOP)) || (result >= (num-1)))
			_i2c_stop(i2c_bit);
	}

	return result;
}

static u32 adapter_func(struct i2c_adapter *adap)
{
	return I2C_FUNC_I2C | I2C_FUNC_NOSTART
		| I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA
		| I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_PROTOCOL_MANGLING;
}

//设备和驱动匹配成功执行
static int adapter_probe(struct platform_device *pdev)
{
	int result;
	uint32_t id;

	printk("%s\r\n", __FUNCTION__);

	//获取设备ID号
	result = of_property_read_u32(pdev->dev.of_node, "id", &id);
	if(result < 0)
	{
		printk("get dev id failed\r\n");
		return result;
	}
	if(id > ADAPTER_NUMBER)
	{
		printk("dev id invalid\r\n");
		return -EINVAL;
	}

	//检查是否占用
	if(adapter_handle[id].use_flag) 
	{
		printk("dev id repetition\r\n");
		return -EINVAL;
	}
	pdev->id = id;

	//标记为已占用
	adapter_handle[id].use_flag = 1;

	//获取时钟延时
	result = of_property_read_u32(pdev->dev.of_node, "delay-us", &adapter_handle[id].delay_us);
	if(result < 0)
	{
		printk("get dev id failed\r\n");
		return result;
	}

	//获取SCL GPIO号
	adapter_handle[id].scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpio", 0);
	if(adapter_handle[id].scl_gpio < 0)
	{
		adapter_handle[id].use_flag = 0;
		printk("get scl_gpio failed\r\n");
		return adapter_handle[id].scl_gpio;
	}
	//申请SCL GPIO
	result = gpio_request(adapter_handle[id].scl_gpio, "scl_gpio");
	if(result != 0)
	{
		adapter_handle[id].use_flag = 0;
		printk("request scl_gpio failed\r\n");
		return result;
	}
	//获取SDA GPIO号
	adapter_handle[id].sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpio", 0);
	if(adapter_handle[id].sda_gpio < 0)
	{
		gpio_free(adapter_handle[id].scl_gpio);
		adapter_handle[id].use_flag = 0;
		printk("get sda_gpio failed\r\n");
		return adapter_handle[id].sda_gpio;
	}
	//申请SDA GPIO
	result = gpio_request(adapter_handle[id].sda_gpio, "sda_gpio");
	if(result != 0)
	{
		gpio_free(adapter_handle[id].scl_gpio);
		adapter_handle[id].use_flag = 0;
		printk("request sda_gpio failed\r\n");
		return result;
	}

	//配置为输出，并输出高电平
	SDA_OUTPUT(&adapter_handle[id], 1);
	SCL_OUTPUT(&adapter_handle[id], 1);

	//初始化I2C适配器
	adapter_handle[id].adapter.owner = THIS_MODULE;
	adapter_handle[id].adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DDC | I2C_CLASS_SPD;
	adapter_handle[id].adapter.nr = -1;
	adapter_handle[id].adapter.algo = &adapter_algorithm;
	adapter_handle[id].adapter.dev.of_node = pdev->dev.of_node;
	adapter_handle[id].adapter.dev.parent = &pdev->dev;
	snprintf(adapter_handle[id].adapter.name, sizeof(adapter_handle[id].adapter.name), "i2c-bus-virtual");
	//添加I2C适配器
	result = i2c_add_adapter(&adapter_handle[id].adapter);
	if(result < 0) {
		gpio_free(adapter_handle[id].sda_gpio);
		gpio_free(adapter_handle[id].scl_gpio);
		adapter_handle[id].use_flag = 0;
		printk("add adapter failed\r\n");
		return result;
	}

	return 0;
}

//设备或驱动卸载时执行
static int adapter_remove(struct platform_device *pdev)
{
	uint32_t id;

	printk("%s\r\n", __FUNCTION__);

	id = pdev->id;
	if(!adapter_handle[id].use_flag)
	{
		printk("verification failed\r\n");
		return -EINVAL;
	}

	i2c_del_adapter(&adapter_handle[id].adapter);
	gpio_free(adapter_handle[id].sda_gpio);
	gpio_free(adapter_handle[id].scl_gpio);

	adapter_handle[id].use_flag = 0;

	return 0;
}

static int __init adapter_drv_init(void)
{
	int i;
	int result;

	printk("%s\r\n", __FUNCTION__);

	for(i=0; i<ADAPTER_NUMBER; i++)
	{
		adapter_handle[i].use_flag = 0;
	}

	//注册平台驱动
	result = platform_driver_register(&adapter_drv);
	if(result != 0)
	{
		printk("add cdev failed\r\n");
		return result;
	}
	return result;
}

static void __exit adapter_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&adapter_drv);
}

module_init(adapter_drv_init);
module_exit(adapter_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("adapter_dev");
